﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Management;
using System.Security.Cryptography;
using System.Windows.Forms;
using System.Net;
using System.Threading;
using System.Diagnostics;
using System.ComponentModel;
using System.Reflection;
using System.IO.Pipes;
using System.IO;

namespace Intorise.Framework
{
    /// <summary>
    /// 软件安全类
    /// </summary>
    public class Security
    {
        private static MD5 md5 = MD5.Create();
        private static string sn = null;
        private static bool exited = false;

        static Security()
        {
#if !DEBUG
            Check();
#endif
            Application.ApplicationExit += Application_ApplicationExit;
        }

        static void Application_ApplicationExit(object sender, EventArgs e)
        {
            exited = true;
        }

        private static void Check()
        {
            return;
            Thread thread = new Thread(new ParameterizedThreadStart(delegate(object o)
            {
                AppConfig config = null;
                try
                {
                    config = AppConfig.LoadSerialNumber();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("加载配置文件时出错.");
                    Console.WriteLine(ex.Message);
                    config = new AppConfig();
                }

                sn = config.SerialNumber;
                Check_0();

            Start:
                string code = GetCode(Application.ProductName);
                Console.WriteLine("Application.ProductName:" + Application.ProductName + "\r\ncode:" + code + "\r\nsn:" + config.SerialNumber);
                ValidateResult result = Validate(Application.ProductName, code, config.SerialNumber);
                if (!result.Success)
                {
                    Thread exitThread = new Thread(new ParameterizedThreadStart(delegate(object o0)
                    {
                        MessageBox.Show(result.Message);
                    }));
                    exitThread.Start();
                    Thread.Sleep(5 * 60 * 1000);
                    CancelEventArgs args = new CancelEventArgs();
                    do
                    {
                        Application.Exit(args);
                    }
                    while (args.Cancel);
                    return;
                }

                Thread.Sleep(1000 * 5);
                goto Start;
            }));
            thread.IsBackground = true;
            thread.Start();
        }

        private static void Check_0()
        {
            Thread thread = new Thread(new ParameterizedThreadStart(delegate(object o)
            {
                NamedPipeClientStream client = null;
                StreamWriter writer = null;
                try
                {
                    client = new NamedPipeClientStream("\\.", "intorise.security");
                    try
                    {
                        client.Connect(10 * 1000);
                    }
                    catch (TimeoutException te) { }
                    if (client.IsConnected)
                    {
                        writer = new StreamWriter(client);
                        writer.WriteLine(sn);
                        writer.Flush();
                        Check1();
                    }
                    else
                    {
                        Check0();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace);
                }
                finally
                {
                    if (writer != null) { writer.Close(); }
                    if (client != null) { client.Close(); }
                }
            }));
            thread.IsBackground = true;
            thread.Start();
        }

        private static void Check0()
        {
            Thread thread = new Thread(new ParameterizedThreadStart(delegate(object o)
            {
                NamedPipeServerStream client = null;
                StreamReader reader = null;
                StreamWriter writer = null;
                NamedPipeClientStream sender = null;
                try
                {
                    do
                    {
                        try
                        {
                            client = new NamedPipeServerStream("intorise.security", PipeDirection.InOut, 10);
                            client.WaitForConnection();
                            if (client.IsConnected)
                            {
                                reader = new StreamReader(client);
                                string newSn = reader.ReadLine();
                                sender = new NamedPipeClientStream("\\.", "intorise.security0", PipeDirection.InOut);
                                sender.Connect();
                                if (sender.IsConnected)
                                {
                                    writer = new StreamWriter(sender);
                                    if (newSn == sn)
                                    {
                                        writer.WriteLine("Used");
                                    }
                                    else
                                    {
                                        writer.WriteLine("Unused");
                                    }
                                    writer.Flush();
                                }
                            }
                        }
                        catch { }
                        finally
                        {
                            if (reader != null) { reader.Close(); }
                            if (client != null) { client.Close(); }
                            if (writer != null) { writer.Close(); }
                            if (sender != null) { sender.Close(); }
                        }
                    } while (!exited);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace);
                }
                finally
                {
                    if (reader != null) { reader.Close(); }
                    if (client != null) { client.Close(); }
                    if (writer != null) { writer.Close(); }
                    if (sender != null) { sender.Close(); }
                }
            }));
            thread.IsBackground = true;
            thread.Start();
        }

        private static void Check1()
        {
            Thread thread = new Thread(new ParameterizedThreadStart(delegate(object o)
            {
                NamedPipeServerStream client = null;
                StreamReader reader = null;
                try
                {
                    client = new NamedPipeServerStream("intorise.security0", PipeDirection.InOut, 10);
                    client.WaitForConnection();
                    if (client.IsConnected)
                    {
                        reader = new StreamReader(client);
                        string newSn = reader.ReadLine();

                        if (newSn == "Used")
                        {
                            Thread exitThread = new Thread(new ParameterizedThreadStart(delegate(object o0)
                            {
                                MessageBox.Show(GetStringFromHexString(used));
                            }));
                            exitThread.Start();
                            Thread.Sleep(10 * 1000);
                            CancelEventArgs args = new CancelEventArgs();
                            do
                            {
                                Application.Exit(args);
                            }
                            while (args.Cancel);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace);
                }
                finally
                {
                    if (reader != null) { reader.Close(); }
                    if (client != null) { client.Close(); }
                }
            }));
            thread.IsBackground = true;
            thread.Start();
        }

        /// <summary>
        /// 获取注册码
        /// </summary>
        /// <param name="softwareName"></param>
        /// <returns></returns>
        public static string GetCode(string softwareName)
        {
            string cpuInfo = "";
            try
            {
                ManagementClass cimobject = new ManagementClass("Win32_Processor");
                ManagementObjectCollection moc = cimobject.GetInstances();
                foreach (ManagementObject mo in moc)
                {
                    cpuInfo = mo.Properties["ProcessorId"].Value.ToString();
                    break;
                }

                String HDid = "";
                cimobject = new ManagementClass("Win32_DiskDrive");
                moc = cimobject.GetInstances();
                foreach (ManagementObject mo in moc)
                {
                    HDid = mo.Properties["Signature"].Value.ToString();
                    break;
                }

                String mac = "";
                cimobject = new ManagementClass("Win32_NetworkAdapterConfiguration");
                moc = cimobject.GetInstances();
                foreach (ManagementObject mo in moc)
                {
                    if ((bool)mo["IpEnabled"] == true)
                    {
                        mac = mo["MacAddress"].ToString();
                        break;
                    }
                }

                //ConsoleBLL.WriteLineError("CPU:"+cpuInfo);
                //ConsoleBLL.WriteLineError("HD:" + HDid);

                mac = "";
                byte[] codeByte = md5.ComputeHash(Encoding.UTF8.GetBytes(softwareName + ":" + cpuInfo + ":" + HDid + ":" + mac + ":" + Application.ProductName));

                cpuInfo = "";
                foreach (byte b in codeByte)
                {
                    cpuInfo += b.ToString("X2");
                }
            }
            catch
            {
                cpuInfo = "TestCode";
            }
            return cpuInfo;
        }

        /// <summary>
        /// 获取注册码
        /// </summary>
        /// <param name="softwareName"></param>
        /// <returns></returns>
        public static string GetCode()
        {
            return GetCode(Application.ProductName);
        }

        /// <summary>
        /// 验证注册码和序列号
        /// </summary>
        /// <param name="softName"></param>
        /// <param name="code"></param>
        /// <param name="serialNumber"></param>
        /// <returns></returns>
        public static ValidateResult Validate(string softName, string code, string serialNumber)
        {
            ValidateResult result = new ValidateResult();
            try
            {
                string validSN = GetSN(code);
                result.Success = validSN.CompareTo(serialNumber) == 0;
                if (!result.Success)
                {
                    result.Message = string.Format(GetStringFromHexString(message0), softName, code, serialNumber);
                    return result;
                }
                return result;
                string url = "http://localhost:49778/www/Check.ashx?soft=" + softName + "&code=" + code + "&sn=" + serialNumber;
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                Stream stream = response.GetResponseStream();
                StreamReader reader = new StreamReader(stream);
                reader.Close();
                response.Close();
                request.Abort();
                string time = reader.ReadToEnd();
                long limit = 0;

                if (!long.TryParse(time, out limit))
                {
                    result.Success = false;
                    result.Message = string.Format(GetStringFromHexString(message0), softName, code, serialNumber);
                    return result;
                }
                if (limit <= 0)
                {
                    result.Success = false;
                    result.Message = string.Format(GetStringFromHexString(message1), softName, code, serialNumber);
                }
                else
                {
                    TimeSpan span = new TimeSpan(limit);
                    result.Success = true;
                    result.TimeLimit = span;
                    result.Message = string.Format(GetStringFromHexString(message2), span, softName, code, serialNumber, DateTime.Now.AddTicks(limit).ToString("yyyyMMdd hh:mm:ss"));
                }
            }
            catch (Exception ex)
            {
                result.Success = false;
                result.Message = GetStringFromHexString(error);
            }
            return result;
        }

        /// <summary>
        /// 验证注册码和序列号
        /// </summary>
        /// <param name="softName"></param>
        /// <param name="code"></param>
        /// <param name="serialNumber"></param>
        /// <returns></returns>
        public static ValidateResult Validate(string code, string serialNumber)
        {
            return Validate(Application.ProductName, code, serialNumber);
        }

        /// <summary>
        /// 获取序列号
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public static string GetSN(string code)
        {
            byte[] codeByte = md5.ComputeHash(Encoding.UTF8.GetBytes(code));
            code = "";
            foreach (byte b in codeByte)
            {
                code += b.ToString("X");
            }
            return code;
        }

        public static void Init()
        {

        }

        /// <summary>
        /// 验证结果类
        /// </summary>
        public struct ValidateResult
        {
            /// <summary>
            /// 验证是否成功
            /// </summary>
            public bool Success;
            /// <summary>
            /// 可用时间Ticks
            /// </summary>
            public TimeSpan TimeLimit;
            /// <summary>
            /// 验证信息
            /// </summary>
            public string Message;
        }

        private static string GetStringFromHexString(string[] temp)
        {
            byte[] datas = GetByteFromHexString(temp);
            return Encoding.UTF8.GetString(datas);
        }

        private static byte[] GetByteFromHexString(string[] temp)
        {
            List<byte> list = new List<byte>();
            byte data = 0;
            foreach (string s in temp)
            {
                if (byte.TryParse(s, System.Globalization.NumberStyles.HexNumber, null, out data))
                {
                    list.Add(data);
                }
                else
                {
                    throw new ArgumentException("文本中包含的文本不是十六进制数字：" + s);
                }
            }

            return list.ToArray();

        }

        private static string[] message0 = new string[] { "E5", "BA", "8F", "E5", "88", "97", "E5", "8F", "B7", "E6", "97", "A0", "E6", "95", "88", "EF", "BC", "8C", "E7", "A8", "8B", "E5", "BA", "8F", "E5", "B0", "86", "E5", "9C", "A8", "35", "E5", "88", "86", "E9", "92", "9F", "E5", "90", "8E", "E5", "85", "B3", "E9", "97", "AD", "EF", "BC", "8C", "E8", "AF", "B7", "E8", "81", "94", "E7", "B3", "BB", "E5", "BC", "80", "E5", "8F", "91", "E8", "80", "85", "EF", "BC", "81", "0A", "E8", "BD", "AF", "E4", "BB", "B6", "EF", "BC", "9A", "7B", "30", "7D", "0A", "E6", "B3", "A8", "E5", "86", "8C", "E7", "A0", "81", "EF", "BC", "9A", "7B", "31", "7D", "0A", "E5", "BA", "8F", "E5", "88", "97", "E5", "8F", "B7", "EF", "BC", "9A", "7B", "32", "7D" };
        private static string[] message1 = new string[] { "E5", "BA", "8F", "E5", "88", "97", "E5", "8F", "B7", "E5", "B7", "B2", "E7", "BB", "8F", "E8", "BF", "87", "E6", "9C", "9F", "EF", "BC", "8C", "E8", "AF", "B7", "E8", "81", "94", "E7", "B3", "BB", "E5", "BC", "80", "E5", "8F", "91", "E8", "80", "85", "EF", "BC", "81", "0A", "E8", "BD", "AF", "E4", "BB", "B6", "EF", "BC", "9A", "7B", "30", "7D", "0A", "E6", "B3", "A8", "E5", "86", "8C", "E7", "A0", "81", "EF", "BC", "9A", "7B", "31", "7D", "0A", "E5", "BA", "8F", "E5", "88", "97", "E5", "8F", "B7", "EF", "BC", "9A", "7B", "32", "7D" };
        private static string[] message2 = new string[] { "20", "E5", "BA", "8F", "E5", "88", "97", "E5", "8F", "B7", "E8", "BF", "98", "E6", "9C", "89", "7B", "30", "7D", "E8", "BF", "87", "E6", "9C", "9F", "EF", "BC", "8C", "E8", "AF", "B7", "E8", "81", "94", "E7", "B3", "BB", "E5", "BC", "80", "E5", "8F", "91", "E8", "80", "85", "E7", "BB", "AD", "E7", "BA", "A6", "EF", "BC", "81", "0A", "E8", "BD", "AF", "E4", "BB", "B6", "EF", "BC", "9A", "7B", "31", "7D", "0A", "E6", "B3", "A8", "E5", "86", "8C", "E7", "A0", "81", "EF", "BC", "9A", "7B", "32", "7D", "0A", "E5", "BA", "8F", "E5", "88", "97", "E5", "8F", "B7", "EF", "BC", "9A", "7B", "33", "7D", "0A", "E8", "BF", "87", "E6", "9C", "9F", "E6", "97", "B6", "E9", "97", "B4", "EF", "BC", "9A", "7B", "34", "7D" };
        private static string[] error = new string[] { "E9", "AA", "8C", "E8", "AF", "81", "E5", "BA", "8F", "E5", "88", "97", "E5", "8F", "B7", "E5", "87", "BA", "E9", "94", "99", "EF", "BC", "8C", "E7", "A8", "8B", "E5", "BA", "8F", "E5", "B0", "86", "E5", "9C", "A8", "35", "E5", "88", "86", "E9", "92", "9F", "E5", "90", "8E", "E5", "85", "B3", "E9", "97", "AD", "E3", "80", "82", "0A", "E8", "AF", "B7", "E8", "81", "94", "E7", "B3", "BB", "E5", "BC", "80", "E5", "8F", "91", "E8", "80", "85", "E8", "8E", "B7", "E5", "BE", "97", "E5", "B8", "AE", "E5", "8A", "A9", "E3", "80", "82" };
        private static string[] used = new string[] { "E5", "BA", "8F", "E5", "88", "97", "E5", "8F", "B7", "E5", "B7", "B2", "E7", "BB", "8F", "E5", "9C", "A8", "E6", "9C", "AC", "E6", "9C", "BA", "E5", "8F", "A6", "E5", "A4", "96", "E7", "9A", "84", "E7", "A8", "8B", "E5", "BA", "8F", "E4", "B8", "AD", "E4", "BD", "BF", "E7", "94", "A8", "EF", "BC", "8C", "E8", "AF", "B7", "E8", "81", "94", "E7", "B3", "BB", "E5", "BC", "80", "E5", "8F", "91", "E8", "80", "85", "EF", "BC", "81" };
    }
}
